package com.demo.security.config;

import com.demo.security.filter.JwtAuthenticationFilter;
import com.demo.security.handler.AccessAuthenticationFailureHandler;
import com.demo.security.properties.AuthenticationProperties;
import com.demo.security.provider.JwtTokenValidationProvider;
import com.demo.security.token.JwtTokenFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 安全登录认证相关配置
 *
 * @author molong
 * @since 2024/5/24
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration {
    /**
     * 认证相关配置
     */
    private final AuthenticationProperties authenticationProperties;

    /**
     * JSON格式化
     */
    private final ObjectMapper objectMapper;


    public WebSecurityConfiguration(AuthenticationProperties authenticationProperties, ObjectMapper objectMapper) {
        this.authenticationProperties = authenticationProperties;
        this.objectMapper = objectMapper;
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        //HttpSecurity中配置放行不起作用,在WebSecurity中配置忽略的路径
        return (web) -> {
            List<RequestMatcher> requestMatchers = authenticationProperties.getIgnorePaths().stream()
                                                           .map(AntPathRequestMatcher::new)
                                                           .collect(Collectors.toList());
            web.ignoring().requestMatchers(new OrRequestMatcher(requestMatchers));
        };
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtTokenFactory jwtTokenFactory) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();
        registry.and()
                .authorizeRequests()
                //任何请求都需要认证
                .anyRequest()
                .authenticated()
                .and()
                //自定义JWT过滤器 验证jwt的token
                .addFilterAfter(new JwtAuthenticationFilter(new AccessAuthenticationFailureHandler(objectMapper),
                        new ProviderManager(new JwtTokenValidationProvider(jwtTokenFactory))),
                        //这个过滤器只处理AuthenticationException和AccessDeniedException两种类型的异常，其他异常直接继续上抛
                        ExceptionTranslationFilter.class)
                .headers()
                .frameOptions()
                .sameOrigin();

        //csrf针对的是session的攻击，使用jwt就不需要这个保护
        registry.and()
                .csrf()
                .disable();
        // 构建过滤链并返回
        return http.build();
    }
}